package com.hanxiaozhang;

import com.hanxiaozhang.autocinfigure.DistributedLockProperties;
import com.hanxiaozhang.exception.DistributedLockException;
import com.hanxiaozhang.util.BeanUtil;
import com.hanxiaozhang.util.ResourceUtil;
import com.hanxiaozhang.util.StringUtil;
import com.hanxiaozhang.util.YamlUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 〈一句话功能简述〉<br>
 * 〈分布式锁工厂创建者〉
 * PS：这里主要实现，怎么去读配置文件
 * <p>
 * 模仿mybatis的设计模式搞一下
 * SqlSessionFactoryBuilder
 * SqlSessionFactory
 *
 * @author hanxinghua
 * @create 2022/9/2
 * @since 1.0.0
 */
@Slf4j
public class DistributedLockFactoryBuilder {


    public DistributedLockFactory build(String yamlPath, String nodeName) {
        Configuration config = null;
        try {
            config = ymalToConfiguration(yamlPath, nodeName);
        } catch (Exception e) {
            log.error("构建DistributedLockFactory失败!");
            throw new DistributedLockException(e);
        }
        return this.build(config);
    }


    public DistributedLockFactory build(DistributedLockProperties properties) {
        Configuration config = propertiesToConfiguration(properties);
        return this.build(config);
    }


    private DistributedLockFactory build(Configuration config) {

        return new DistributedLockFactory(config);
    }


    /**
     * yaml转换成Configuration
     *
     * @param yamlPath
     * @param nodeName
     * @return
     * @throws Exception
     */
    private Configuration ymalToConfiguration(String yamlPath, String nodeName) throws Exception {

        InputStream inputStream = ResourceUtil.getInputStream(yamlPath);
        Map map = YamlUtil.parse(inputStream, nodeName);
        Configuration config = mapToBean(map, Configuration.class);
        return config;
    }


    /**
     * properties转换成Configuration
     *
     * @param properties
     * @return
     */
    private Configuration propertiesToConfiguration(DistributedLockProperties properties) {
        Configuration config = new Configuration();
        BeanUtil.copyPropertiesIgnoreNull(properties, config);
        Integer zkClearInvalidNodeBeforeTime = properties.getZkClearInvalidNodeBeforeTime().getValue();
        config.setZkClearInvalidNodeBeforeTime(zkClearInvalidNodeBeforeTime);
        return config;
    }


    /**
     * 将Map中的键值对，封装进实体对象属性中
     *
     * @param map
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> T mapToBean(Map<String, Object> map, Class<T> tClass) throws Exception {
        T t = tClass.newInstance();
        if (map.isEmpty()) {
            return t;
        }
        Map<String, Integer> fieldMap = new HashMap<>(16);
        Field[] fields = tClass.getDeclaredFields();
        for (Field field : fields) {
            fieldMap.put(field.getName(), 1);
        }
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (fieldMap.containsKey(entry.getKey())) {
                Field field = tClass.getDeclaredField(entry.getKey());
                field.setAccessible(true);
                if (entry.getValue().getClass().equals(field.getType())) {
                    field.set(t, entry.getValue());
                } else {
                    // 特殊处理
                    if ("zkClearInvalidNodeBeforeTime".equals(entry.getKey())) {
                        field.set(t, convertZkClearInvalidNodeBeforeTime(entry.getValue()));
                        continue;
                    }
                    // 遇到问题再完善
                }
            }
        }
        return t;
    }

    /**
     * 转换zkClearInvalidNodeBeforeTime
     *
     * @param value
     * @return
     */
    private Integer convertZkClearInvalidNodeBeforeTime(Object value) {

        if (value == null) {
            return 86400;
        }
        Integer sum = 1;
        String str = String.valueOf(value);
        String[] array = str.split("\\*");
        for (String item : array) {
            sum *= Integer.parseInt(item);
        }
        return sum;
    }

    /**
     * 将String 转换成目标类型
     *
     * @param string
     * @param t
     * @return
     * @throws Exception
     */
    private Object stringToTarget(String string, Class<?> t) throws Exception {

        boolean nullOrEmpty = StringUtil.isBlank(string);
        if (double.class.equals(t)) {
            return nullOrEmpty ? 0 : Double.parseDouble(string);
        } else if (long.class.equals(t)) {
            return nullOrEmpty ? 0 : Long.parseLong(string);
        } else if (int.class.equals(t)) {
            return nullOrEmpty ? 0 : Integer.parseInt(string);
        } else if (float.class.equals(t)) {
            return nullOrEmpty ? 0 : Float.parseFloat(string);
        } else if (short.class.equals(t)) {
            return nullOrEmpty ? 0 : Short.parseShort(string);
        } else if (boolean.class.equals(t)) {
            return nullOrEmpty ? 0 : Boolean.parseBoolean(string);
        } else if (Number.class.isAssignableFrom(t)) {
            return t.getConstructor(String.class).newInstance(nullOrEmpty ? "0" : string);
        } else {
            return nullOrEmpty ? "" : t.getConstructor(String.class).newInstance(string);
        }
    }

}
